/**
 * Created by tanbingqin on 2020/4/27.
 */
import {messages} from "share/common";
import React from 'react';
import ReactDOM from 'react-dom';
import { Icon, Button, Row, Col, Spin, Input, Tag, Checkbox } from 'antd'
import { EventUtils } from 'share/common'
import 'styles/components/template/multi-selector/multi-selector.scss'
import selectorData from 'share/selectorData'
import httpFetch from 'share/httpFetch'
const Search = Input.Search;
import debounce from 'lodash.debounce'

class MultiSelector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isShowSearch: false,
      value: [],
      options: [],
      searchData: [], //前端搜索结果
      loading: false,
      keyword: '',
      focusedKey: '' //tag选中的高亮key
    };
    this.handleSearchStep2 = debounce(this.handleSearchStep2, 500);
  }

  componentDidMount() {
    const { multiSelector } = this.refs;
    EventUtils.addHandler(multiSelector, 'keydown', this.handleKeyDown);
    if('value' in this.props)
      this.setValue(this.props.value);
  };

  componentWillUnmount() {
    const { multiSelector } = this.refs;
    EventUtils.removeHandler(multiSelector, 'keydown', this.handleKeyDown);
  }

  componentWillReceiveProps(nextProps) {
    if('value' in nextProps)
      this.setValue(nextProps.value);
  }

  setValue = value => {
    let selectorItem = this.getSelectorItem();
    const { key, label, labelKey } = selectorItem;
    if(value && Array.isArray(value)) {
      let valueOptions = value.map(option => ({
        key: option[key], //不支持非字符串的key
        label: typeof label === 'string' ? option[label] : (typeof label(option) === 'string' ? label(option) : option[labelKey]),
        data: option
      }));
      this.setState({ value: valueOptions });
    } else {
      this.setState({ value: [] });
    }
  };

  handleKeyDown = (e) => {
    const { scrollBlock } = this.refs;
    const { newline } = this.props;
    const { value } = this.state;
    if (!newline && scrollBlock && value.length) {
      let scrollDom = ReactDOM.findDOMNode(scrollBlock);
      let currentFocusWidth = this.findFocusWidth(scrollDom.childNodes || scrollBlock.childNodes);
      let innerWidth = scrollDom.scrollWidth;
      let averageWidth = innerWidth / value.length;
      let realityWidth = currentFocusWidth || averageWidth;
      let currentLeft = scrollDom.scrollLeft;
      let toLeft = 0;
      //键盘左键
      if (e.keyCode === 37) {
        toLeft = currentLeft - realityWidth > 0 ? currentLeft - realityWidth : 0;
        this.changeFocusedKey('left');
      }
      //键盘右键
      if (e.keyCode === 39) {
        toLeft = currentLeft + realityWidth;
        this.changeFocusedKey('right');
      }
      if (e.keyCode === 37 || e.keyCode === 39) {
        if (scrollDom.scrollTo) {
          scrollDom.scrollTo({
            left: toLeft,
            behavior: "smooth"
          });
        } else {
          scrollDom.scrollLeft = toLeft;
        }
      }
    }
  };

  findFocusWidth = (nodes) => {
    const { focusedKey } = this.state;
    let width = 0;
    if (nodes && nodes.length) {
      nodes.forEach(node => {
        if (node.id && node.id === focusedKey && node.clientWidth) {
          width = node.clientWidth + 8;
        }
      });
    }
    return width;
  };

  getSelectorItem = () => {
    const { selectorItem, type } = this.props;
    return selectorItem || selectorData[type];
  };

  getOptions = () => {
    const { params, filter } = this.props;
    let selectorItem = this.getSelectorItem();
    const { service, url, map, listKey, key, label, labelKey, descriptionKey, enableKey, disableKey } = selectorItem;
    this.setState({ loading: true });
    let fetch = service ? service() : httpFetch.get(url, { ...params });
    fetch.then(res => {
      let options = [];
      if(map)
        options = map(res.data);
      else {
        if(listKey) {
          let keys = selectorItem.listKey.split('.');
          options = res.data;
          keys.map(key => {
            options = options[key];
          })
        } else {
          options = res.data;
        }
      }
      this.setState({
        loading: false,
        options: options.filter(filter).map(option => ({
          key: option[key], //不支持非字符串的key
          label: typeof label === 'string' ? option[label] : (typeof label(option) === 'string' ? label(option) : option[labelKey]),
          description: descriptionKey ? (typeof descriptionKey === 'string' ? option[descriptionKey] : descriptionKey(option)) : undefined,
          data: option,
          disable: (enableKey && !option[enableKey]) || option[disableKey]
        }))
      });
    }).catch(e => {
      this.setState({ loading: false });
    })
  };

  handleShowSearchBlock = (isFocus) => {
    const { isShowSearch: oldIsShowSearch } = this.state;
    if (isFocus) {
      if (this.timer) {
        clearTimeout(this.timer);
      }
      this.setState({
        isShowSearch: true
      }, () => {
        if (!oldIsShowSearch) {
          //聚焦打开下拉框
          //把this.getOptions();从componentDidMount放到这，是因为props里的params会变，所以在每次打开的时候获取取值范围
          this.getOptions();
        }
      });
    } else {
      this.timer = setTimeout(() => {
        this.setState({
          isShowSearch: false
        }, this.resetAll);
      }, 100);
    }
  };

  //在失焦后重置搜索展示框
  resetAll = () => {
    this.setState({searchData: [], keyword: '', focusedKey: ''});
  };

  //渲染option展示结果
  renderSearchResult = () => {
    const { options, searchData, keyword, loading } = this.state;
    let selectorItem = this.getSelectorItem();
    const { enableKey, disableKey } = selectorItem;
    let showList = keyword.length ? searchData : options;

    if (loading) {
      return <div>&nbsp;</div>;
    }

    return showList.length ? (
      <div style={{overflowY: 'auto', maxHeight: 160}}>
        {showList.map((option, index) => {
          return (
            <div
              className={`ant-select-dropdown-menu-item ${this.isSelect(option) ? 'ant-select-dropdown-menu-item-selected' : ''}`}
              key={option.key}
              onClick={() => this.handleSelect(option)}
            >
              <section className="multiple-option">
                <div className="multiple-option-title" style={{whiteSpace: 'normal', lineHeight: '18px'}}>
                  {option.label}
                  {(enableKey || disableKey) && (
                    <span style={{color: '#FF6680'}}>{option.disable ? `(${messages('common.status.disable')/*禁用*/})` : ''}</span>
                  )}
                </div>
                {option.description && (
                  <div className="multiple-option-content" style={{whiteSpace: 'normal', marginTop: '4px'}}>{option.description}</div>
                )}
              </section>
            </div>
          )
        })}
      </div>
    ) : (
      <div>{messages('common-1.key294')/*无搜索结果*/}</div>
    )
  };

  //是否是选中的option
  isSelect = (option) => {
    let { value } = this.state;
    let isHas = !!value.filter(item => item.key === option.key).length;
    return isHas;
  };

  handleSelect = (option) => {
    const { single } = this.props;
    let { value } = this.state;
    let isHas = !!value.filter(item => item.key === option.key).length;
    if (isHas) {
      value = value.filter(item => item.key !== option.key);
    } else {
      if (single) {
        value = [];
      }
      value.push(option);
    }
    this.setState({value}, () => {
      this.dispatchOnchange();
      if (!isHas) {
        //新增一个的时候划到底部
        this.scrollToEnd();
        this.focusToEnd();
      }
    });
  };

  handleSelectTag = (e, key) => {
    this.setState({focusedKey: key});
  };

  removeValue = (e, key) => {
    e.stopPropagation();
    e.preventDefault();
    let { value } = this.state;
    value = value.filter(item => item.key !== key);
    this.setState({value}, this.dispatchOnchange);
  };

  removeAllValue = () => {
    this.setState({value: []}, this.dispatchOnchange);
  };

  dispatchOnchange() {
    const { value } = this.state;
    const { onChange } = this.props;
    onChange && onChange(value.map(v => v.data));
  }

  handleSearch = (value) => {
    this.setState({keyword: value, loading: true});
    this.handleSearchStep2(value);
  };

  handleSearchStep2 = (value) => {
    const { options } = this.state;
    let selectorItem = this.getSelectorItem();
    const { enableKey, disableKey } = selectorItem;
    let disableStr = `(${messages('common.status.disable')/*禁用*/})`;
    //先只支持根据label搜索
    let searchData = options.filter(item => {
      if (item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
        return true;
      }
      if (item.description && item.description.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
        return true;
      }
      if ((enableKey || disableKey) && item.disable && disableStr.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
        return true;
      }
    });
    this.setState({searchData, loading: false});
  };

  onCheckAllChange = e => {
    const { options } = this.state;
    this.setState({
      value: e.target.checked ? options : [],
    }, () => {
      this.dispatchOnchange();
      this.scrollToEnd();
      this.focusToEnd();
    });
  };

  //划动到底部
  scrollToEnd = () => {
    const { scrollBlock } = this.refs;
    const { newline } = this.props;
    const { value } = this.state;
    if (!newline && scrollBlock && value.length) {
      let scrollDom = ReactDOM.findDOMNode(scrollBlock);
      let innerWidth = scrollDom.scrollWidth;
      if (scrollDom.scrollTo) {
        scrollDom.scrollTo({
          left: innerWidth,
          behavior: "smooth"
        });
      } else {
        scrollDom.scrollLeft = innerWidth;
      }
    }
  };

  //value最后一个tag标记foucs
  focusToEnd = () => {
    const { newline } = this.props;
    const { value } = this.state;
    if (!newline && value && value.length) {
      let lastItem = value[value.length - 1];
      let focusedKey = lastItem.key;
      this.setState({focusedKey});
    }
  };

  //type left往左边focus right往右边focus
  changeFocusedKey = (type) => {
    const { newline } = this.props;
    const { value, focusedKey } = this.state;
    if (!newline && value && value.length && focusedKey) {
      let focusIndex = -1;
      value.forEach((item, index) => {
        if (item.key === focusedKey) {
          focusIndex = index;
        }
      });
      if (focusIndex > -1) {
        focusIndex = type === 'left' ? focusIndex - 1 : focusIndex + 1;
        focusIndex = focusIndex < 0 ? 0 : (focusIndex > value.length - 1 ? value.length - 1 : focusIndex);
      }
      this.setState({focusedKey: value[focusIndex].key});
    }
  };

  renderMultiTxt = () => {
    const { value } = this.state;
    let labelList = [];
    value && !!value.length && value.map((item, index) => {
      labelList.push(item.label);
    });
    return labelList.join(',');
  };

  render() {
    const { isShowSelectAll, newline, disabled, isAll, single, dropDownStyle, showArrow } = this.props;
    const { value, isShowSearch, loading, keyword, options, focusedKey } = this.state;
    return (
      <div className={`multi-selector-block ${newline ? '' : 'multi-selector-block-line'}`} ref="multiSelector">
        {disabled && (
          <Input placeholder={messages('common-1.key52')/*请选择temp*/} value={isAll ? messages('common-1.key127')/*已选择全部*/ : this.renderMultiTxt()} disabled />
        )}
        {!disabled && (
          <div
            tabIndex="1"
            className={`fake-input ${isShowSearch ? 'fake-input-open' : ''}`}
            onFocus={() => this.handleShowSearchBlock(true)}
            onBlur={() => this.handleShowSearchBlock(false)}
          >
            {value && !!value.length && (
              <div>
                {!single && (
                  <div className={`${newline ? 'margin-right-20' : 'scroll-block'}`} ref="scrollBlock">
                    {value.map((item, index) => {
                      return (
                        <Tag
                          closable
                          id={item.key}
                          onClose={(e) => this.removeValue(e, item.key)}
                          className={`tag-item ${focusedKey === item.key ? 'tag-item-border' : ''}`}
                          onClick={(e) => this.handleSelectTag(e, item.key)}
                        >
                          {item.label}
                        </Tag>
                      )
                    })}
                  </div>
                )}
                {single && (
                  <div className="margin-right-20">
                    {value[0].label}
                  </div>
                )}
                <span className="ant-select-selection__clear" onClick={this.removeAllValue} />
              </div>
            )}
            {(!value || !value.length) && (
              <span style={{color: '#bebdbf'}}>{messages('common-1.key52')/*请选择temp*/}</span>
            )}
            {showArrow && (
              <span className="ant-select-arrow" />
            )}
          </div>
        )}
        {isShowSearch && !disabled && (
          <div className="drop-down-block"
               style={dropDownStyle}
               tabIndex="1"
               onFocus={() => this.handleShowSearchBlock(true)}
               onBlur={() => this.handleShowSearchBlock(false)}>
            <div>
              <Row style={{marginTop: '10px'}} type="flex" gutter={10} align="middle">
                <div style={{flex: 1}}>
                  <Search
                    placeholder={messages('common-1.key416')/*请输入搜索内容*/}
                    value={keyword}
                    onChange={(e) => this.handleSearch(e.target.value)}
                  />
                </div>
                {isShowSelectAll && !single && (
                  <div style={{textAlign: 'right', flex: 'none'}}>
                    <Checkbox
                      indeterminate={value.length && value.length < options.length}
                      onChange={this.onCheckAllChange}
                      checked={value.length && value.length === options.length}
                    >
                      {messages('common.all')/*全部*/}
                    </Checkbox>
                  </div>
                )}
              </Row>
              <Spin spinning={loading}>
                <div style={{padding: '10px 0'}}>
                  {this.renderSearchResult()}
                </div>
              </Spin>
            </div>
          </div>
        )}
      </div>
    )
  }

}

MultiSelector.propTypes = {
  type: React.PropTypes.string,
  selectorItem: React.PropTypes.object,
  params: React.PropTypes.object,
  filter: React.PropTypes.func,
  isShowSelectAll: React.PropTypes.bool, //是否展示全选当前，在不分页的情况下使用
  newline: React.PropTypes.bool,  //内容是否可换行
  disabled: React.PropTypes.bool, //整个控件是否不可操作
  isAll: React.PropTypes.bool, //是否是增量的全选，存的是全选关系，不是具体的选择项，用来控制disabled下的提示语
  single: React.PropTypes.bool,  //是否单选 single为true的情况下不支持isShowSelectAll
  dropDownStyle: React.PropTypes.object, //下拉框样式
  showArrow: React.PropTypes.bool, //是否显示下拉小箭头
};

MultiSelector.defaultProps={
  params: {},
  filter: option => true,
  isShowSelectAll: false,
  newline: false,
  disabled: false,
  isAll: false,
  single: false,
  dropDownStyle: {},
  showArrow: true,
};

export default MultiSelector;
